package NWish
{
	import NWish.Interface.IApp;
	import NWish.Interface.ILogger;
	import NWish.json.Json;
	import NWish.properties.object3ds.Scene3DProperties;
	import NWish.properties.other.FileSystemProperties;
	import NWish.utils.NWLoader;
	
	import away3d.entities.Mesh;
	import away3d.events.AssetEvent;
	import away3d.library.AssetLibrary;
	import away3d.library.assets.AssetType;
	import away3d.loaders.parsers.*;
	
	import com.adobe.mp3.MP3Decoder;
	
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.display.Loader;
	import flash.events.*;
	import flash.net.URLLoaderDataFormat;
	import flash.utils.ByteArray;
	
	
	public class FileSystem
	{
		//
		protected var _app:IApp;
		//public function get parent(){return _app;}
		
		//
		public var extra;
		
		
		//
		public const _sceneExtension = '.scene';
		public const _objectExtension = '.json';
		
		//private const ASSET_SCENE_NAME = 'scene';
		
		
		//
		private var _sceneName:String = 'unknow_scene';
		
		//private var _resourcePath:String = 'assets\\';
		
		//
		private var _resMap 		= new Object();
		private var _resRefCount 	= new Object();
		private var _fileDateMap 	= new Object();
		private var _resPaths 		= new Object();
		
		
		private var _assetLibrary:AssetLibrary = new AssetLibrary(null);
		
		
		public function FileSystem(app)
		{
			//
			_app = app;
			
			//
			//_app.rootSprite.addEventListener(NWEvent.SELSCT_OBJECT,	onSelectObject);
			_app.rootSprite.addEventListener(NWEvent.CLEAR_SCENE,	onClearScene);
		}
		
		public function init()
		{
			//var lib = AssetLibrary.getInstance(ASSET_SCENE_NAME);
			_assetLibrary.addEventListener(AssetEvent.ASSET_COMPLETE, onAssetComplete);
		}
		
		public function get scene()
		{
			var away3d = _app.getPlugin('Away3d');
			if(away3d.view)
				return away3d.view.scene;
		}
		
		public function get view()
		{
			var away3d = _app.getPlugin('Away3d');
			return away3d.view;
		}
		
		public function get camera()
		{
			var away3d = _app.getPlugin('Away3d');
			if(away3d.view)
				return away3d.view.camera;
		}
		
		public function get sceneName()
		{
			return _sceneName;
		}
		public function set sceneName(v)
		{
			_sceneName = v;
		}

		public function getPaths()
		{
			var ps = [];
			for(var p in _resPaths)
				ps.push(p);

			return ps;
		}
		public function get resPaths()
		{
			return _resPaths;
		}
		private function addResPath(file_name,path)
		{
			if(path && path != '')
			{
				if(_resPaths[path] == null)
					_resPaths[path] = [];
				
				_resPaths[path].push(file_name);
				
				_app.NWEventDispatcher.dispatchEvent(new NWEvent(NWEvent.LOADED_RESOURCE,path + '/' + file_name));
			}
		}
		
		
		public function getResource(name:String)
		{
			if(_resRefCount[name] != null)
			{
				_resRefCount[name] += 1;
				return _resMap[name];
			}
			
			ILogger.log('cannot find file : ' + name);
		}
		
		public function get fileNames()
		{
			var names = [];
			for (var n in _resMap)
				names.push(n);
			return names;
		}
		
		public function getFileNames(...finds)
		{
			if(finds[0] is Array)
				finds = finds[0];
			
			var names = [];
			
			for each(var f in finds)
			{
				for (var name:String in _resMap)
				{
					var pos = name.search(f);
					if(pos >= 0)
						names.push(name);
				}
			}
			return names;
		}
		
		public function get resRefCount()
		{
			return _resRefCount;
		}

		/*public function newScene(name)
		{
			_sceneName = name;
			//_resourcePath = '';
			extra = null;
			
			_app.rootSprite.dispatchEvent(new NWEvent(NWEvent.CLEAR_SCENE,null));
			_app.rootSprite.dispatchEvent(new NWEvent(NWEvent.NEW_SCENE,null));
		}*/
		
		//
		public function openScene(name:String,is_import = false)
		{
			new NWLoader(name,onLoadResComplete,URLLoaderDataFormat.TEXT);
			
			var _this = this;
			function onLoadResComplete(data):void
			{
				var json:String = data;
				
				var dict:Object = Json.decode( json,false );
				
				new FileSystemProperties(_app,name,is_import).load(dict,_this,null,null);
			}
		}
		
		
		public function removeResource(path = null) : void
		{
			for each(var f in _resMap)
			{
				if(f is BitmapData)
					(f as BitmapData).dispose();
			}
			
			_resMap = new Object();
			_resRefCount = new Object();
			_fileDateMap = new Object();
			_resPaths = new Object();
			//_assetLibrary = new AssetLibrary(null);
		}
		
		//
		private function openSceneFile(name):void
		{
			//
			var scene_json = _app.fileSystem.getResource(name);
			
			
			//
			//_resourcePath = '';
			extra = null;
			_app.rootSprite.dispatchEvent(new NWEvent(NWEvent.CLEAR_SCENE,null));
			
			
			new FileSystemProperties(_app,name).load(scene_json,this,null,null);
		}
		
		//
		private function importSceneFile(name):void
		{
			//
			var scene_json = _app.fileSystem.getResource(name);
			
			for (var k:String in scene_json)
			{
				new Scene3DProperties(_app).loadObject3D(k,scene_json[k],scene);
			}
		}
		
		private function loadBitmap(name,resource_path,data):void
		{
			var load:Loader = new Loader();
			load.loadBytes(data);
			load.contentLoaderInfo.addEventListener(Event.COMPLETE, onLoadComplete);
			
			function onLoadComplete(e)
			{
				load.contentLoaderInfo.removeEventListener(Event.COMPLETE, onLoadComplete);
				
				//
				var bmd:BitmapData = (load.content as Bitmap).bitmapData;
				if(Misc.isBitmapDataValid(bmd))
				{
					_resMap[name] = bmd;
					_resRefCount[name] = 0;
					_fileDateMap[name] = data;
					addResPath(name,resource_path);
					
					ILogger.log("add bitmap : " + name);
				}
				else
				{
					ILogger.log("Invalid bitmap! Must be power of 2 and not exceeding 2048", name);
				}
				
				loadOneFileComplete();
			}
		}
		
		private function loadMp3(name,resource_path,data):void
		{
			var mp3d:MP3Decoder = new MP3Decoder();
			mp3d.decode(data,handler);
			
			function handler(sndClass:Class):void
			{
				var snd = new sndClass();
				_resMap[name] = snd;
				_resRefCount[name] = 0;
				addResPath(name,resource_path);
				
				loadOneFileComplete();
			}
		}
		
		private function loadJson(name,resource_path,data):void
		{
			var json = data;
			if(data is ByteArray)
				json =  data.readUTFBytes(data.bytesAvailable);

			var dict:Object = Json.decode( json,false );
			
			_resMap[name] = dict;
			_resRefCount[name] = 0;
			addResPath(name,resource_path);
			
			loadOneFileComplete();
			//_fileDateMap[name] = data;
		}
		
		private function onAssetComplete(e:AssetEvent)
		{
			var type : String = e.asset.assetType;
			
			var ass = e.asset;
			if(_resMap[ass.assetNamespace] && ass is Mesh)
			{
				var file = _resMap[ass.assetNamespace];
				file.dispose(true);
			}
			
			
			if (type == AssetType.CONTAINER)
			{
				//this.addChild(ObjectContainer3D(ev.asset));
				throw new Error();
			}
			else if (type == AssetType.GEOMETRY)
			{
				//
				if(ass.assetNamespace.search('.obj') != -1)
				{
					var name = ass.name = ass.assetNamespace;
					_resRefCount[name] = 0;
					_resMap[name] = ass;
					addResPath(name,_curMeshResourcePath);
					//_fileDateMap[name] = data;
					ILogger.log("add mesh : " + name);
				}
				else if(ass.assetNamespace.search('.3ds') != -1)
				{
					var name = ass.name + '_' + ass.assetNamespace;
					_resRefCount[name] = 0;
					_resMap[name] = ass;
					addResPath(name,_curMeshResourcePath);
					//_fileDateMap[name] = data;
					ILogger.log("add mesh : " + name);
				}
				else if(ass.assetNamespace.search('.md5mesh') != -1)
				{
					_resRefCount[ass.assetNamespace] = 0;
					_resMap[ass.assetNamespace] = ass;
					addResPath(ass.assetNamespace,_curMeshResourcePath);
					//_fileDateMap[name] = data;
					ILogger.log("add mesh : " + ass.assetNamespace);
				}
				else
				{
					throw new Error();
				}
			}
			else if(type == AssetType.ANIMATION)
			{
				ass.name = (ass.assetNamespace as String).replace('.md5anim','');
				_resRefCount[ass.assetNamespace] = 0;
				_resMap[ass.assetNamespace] = ass;
				addResPath(ass.assetNamespace,_curMeshResourcePath);
				//_fileDateMap[name] = data;
				ILogger.log("add animation : " + ass.assetNamespace);
			}
			else if(type == AssetType.SKELETON)
			{
				ILogger.log("add skeleton : " + ass.assetNamespace);
				return;
			}
			else
			{
				//ILogger.log("add mesh : " + ass.assetNamespace);
				throw new Error();
			}
			
			//
			loadOneFileComplete();
		}
		
		
		private var _loadFilesNum;
		private var _loadFilesComplete;
		public function loadFilesCompleteListener(num,complete)
		{
			if(num == 0)
			{
				complete();
				return;
			}
			
			_loadFilesNum = num;
			_loadFilesComplete = complete;
		}
		
		protected function loadOneFileComplete()
		{
			if(_loadFilesComplete)
			{
				-- _loadFilesNum;
				if(_loadFilesNum == 0)
				{
					_loadFilesComplete();
					_loadFilesComplete = null;
					_loadFilesNum = null;
				}
			}
		}
		
		private var _curMeshResourcePath;
		private function loadMesh(name,resource_path,data)
		{
			_curMeshResourcePath = resource_path;
			
			var alt;
			
			//
			if(name.search('.md5mesh') != -1)
			{
				_fileDateMap[name] = data;
				alt = _assetLibrary.parseData(data, new MD5MeshParser(), null, name);
			}
			else if(name.search('.md5anim') != -1)
			{
				alt = _assetLibrary.parseData(data, new MD5AnimParser(), null, name);
			}
			else if(name.search('.obj') != -1)
			{
				_fileDateMap[name] = data;
				alt = _assetLibrary.parseData(data,new OBJParser(/*_resourcePath*/), null, name);
				//ILogger.log('todo ... load .obj file!');
			}
			else if(name.search('.3ds') != -1)
			{
				//todo test
				_fileDateMap[name] = data;
				alt = _assetLibrary.parseData(data,new Max3DSParser(), null, name);
				//ILogger.log('todo ... load .3ds file!');
			}
			else if(name.search('.ac') != -1)
			{
				//todo test
				_fileDateMap[name] = data;
				alt = _assetLibrary.parseData(data,new AC3DParser(), null, name);
				//ILogger.log('todo ... load .ac file!');
			}
			else if(name.search('.awd') != -1)
			{
				//todo test
				_fileDateMap[name] = data;
				alt = _assetLibrary.parseData(data,new AWD1Parser(), null, name);
				//ILogger.log('todo ... load .awd file!');
			}
			else if(name.search('.md2') != -1)
			{
				//todo test
				_fileDateMap[name] = data;
				alt = _assetLibrary.parseData(data,new MD2Parser(), null, name);
				//ILogger.log('todo ... load .md2 file!');
			}
			
			if(alt)
				return true;
			
			return false;
		}
		
		public function addFileData(name,resource_path,data):void
		{
			//
			if(name.search('.jpg') != -1
			|| name.search('.png') != -1)
			{
				loadBitmap(name,resource_path,data);
			}
			else if(name.search('.mp3') != -1)
			{
				loadMp3(name,resource_path,data);
			}
			else if(name.search('.scene') != -1
				 || name.search('.json') != -1)
			{
				loadJson(name,resource_path,data);
			}
			else if(loadMesh(name,resource_path,data) == false)
			{
				ILogger.log('cannot read the file : ' + name);
			}
		}
		
		public function loadFiles(resPaths,complete)
		{
			var num = 0;
			for each(var p in resPaths)
			{
				num += p.length;
			}
			
			loadFilesCompleteListener(num,complete);
			
			_app.NWEventDispatcher.dispatchEvent(new NWEvent(NWEvent.LOAD_RESOURCE_NUM,num));
			
			for(var path in resPaths)
			{
				var ress = resPaths[path];
				for each(var f in ress)
					loadFile(f,path);
			}
		}
		
		private function loadFile(f:String,resource_path)
		{
			var dataFormat = URLLoaderDataFormat.BINARY;
			if(f.search('.json') != -1)
				dataFormat = URLLoaderDataFormat.TEXT;
			
			new NWLoader(resource_path + '/' + f,onComplete,dataFormat);
			function onComplete(data):void
			{
				addFileData(f,resource_path, data);
			}
		}
		
		private function onClearScene(e:NWEvent)
		{
			//Refresh res
			for(var k:String in _resMap)
			{
				var f = _resMap[k];
				if(f is BitmapData)
				{
					if(_resRefCount[k] > 0)
					{
						var data = _fileDateMap[k];
						loadBitmap(k, null, data);
					}
				}
				else if(_fileDateMap[k] && loadMesh(k,null,_fileDateMap[k]) == false)
				{
					throw new Error();
				}
			}
		}
		
	}
	
	
}

